òɾۿûѧϰʹá
ԭַhttps://www.joinquant.com/post/12666

ԭһ˵ʽ鵽ԭĺ߽ۡ


ԭĲԴ£

# ¡Ծۿ£https://www.joinquant.com/post/1667
# ⣺ֶСֵŻ v2.0.7 [2016.11.16]
# ߣMorningstar
import math
import numpy as np
import pandas as pd
from pandas import DataFrame,Series
import pickle
import time
import datetime
import jqdata
import talib as tb
import sklearn
from sklearn.decomposition import PCA
from sklearn.tree import DecisionTreeRegressor
from sklearn.ensemble import AdaBoostClassifier,GradientBoostingClassifier,RandomForestRegressor,RandomForestClassifier
from sklearn import cross_validation, metrics,svm,preprocessing  
from sklearn.metrics import mean_squared_error
from sklearn.cross_validation import train_test_split
from sklearn.grid_search import GridSearchCV 
from sklearn.svm import SVR  
from sklearn.externals import joblib
from sklearn.model_selection import learning_curve
from sklearn.linear_model import LinearRegression
'''
Сֵʱ

ָƵʵĵգڵÿָʱ䣬㻦300ָ֤500ָǰ20
2ָ20ǷһΪѡɵ֣֮ѭ

ֹԣ

    ֹ(ѡ)
        1. ÿȡǰ130յͼۺ߼ۣߴ͵ֹ֣ͣס
        2. ÿжϴǷֻѻֲֹֹͣףڶֹͣ
           һ졣

    ֹ(ѡ)
        ÿжϸǷӳֲֺ߼ۻسȣɻسֵƽùɳֲ

    ֹ()
        ÿָʱ䣬㻦300ָ֤500ָǰ20Ƿ2ָǷΪ
        ֣õּ´εٲ
'''
from six import StringIO
import tradestat
#import ind
from ind import *
#from blacklist import *

# blacklist.py
# оｨļblacklist.pyȻδ뿽blacklist.py
# ģеʱֻҪоݼɣڲ޸ģд
# ޸ĺ

# ùƱ
# гҼ˹ĹƱ
# ע1. ʱЧԣزʱòʹãģ⽻׽ʹ
#     2. һģߴݷռƱʱ
def get_blacklist():
    # һʱ 2016.7.10 by ɳ
    # ƺɷݡ̫հҵһ2016ֱͣз
    blacklist = ["600656.XSHG","300372.XSHE","600403.XSHG","600421.XSHG","600733.XSHG","300399.XSHE",
                 "600145.XSHG","002679.XSHE","000020.XSHE","002330.XSHE","300117.XSHE","300135.XSHE",
                 "002566.XSHE","002119.XSHE","300208.XSHE","002237.XSHE","002608.XSHE","000691.XSHE",
                 "002694.XSHE","002715.XSHE","002211.XSHE","000788.XSHE","300380.XSHE","300028.XSHE",
                 "000668.XSHE","300033.XSHE","300126.XSHE","300340.XSHE","300344.XSHE","002473.XSHE"]
    return blacklist

def before_trading_start(context):
    cur_time = context.previous_date
    cur_time = datetime.datetime.strftime(cur_time,'%Y-%m-%d')
    
    print(g.data_.index[0],cur_time)
    print(g.data_.index[0]==cur_time)
    g.stocks = g.data_.where(g.data_==1).loc[cur_time,:].dropna(axis = 0).index.values
    

def after_trading_end(context):
    #log.info("==> after trading end @ %s", str(context.current_dt))
    g.trade_stat.report(context)

    reset_day_param()
    
    # õǰδɶ
    orders = get_open_orders()
    for _order in orders.values():
        log.info("canceled uncompleted order: %s" %(_order.order_id))
    pass

def initialize(context):
    log.info("==> initialize @ %s", str(context.current_dt))
    
    # 
    set_commission(PerTrade(buy_cost=0.0003, sell_cost=0.0013, min_cost=5))
    # û׼ָ300ָ '000300.XSHG'
    set_benchmark('000300.XSHG')
    # 趨Ϊٷֱ
    # ûеset_slippage, ϵͳĬϵĻPriceRelatedSlippage(0.00246)
    #set_slippage(PriceRelatedSlippage(0.004))
    # ʹʵ۸ز(ģƼˣزע)
    set_option('use_real_price', True)

    # ͳģ
    g.trade_stat = tradestat.trade_stat()

    # òԲ
    # ҪΪ֮ǰСֵԣ֤֮ǰس
    # Ҫģ½
    set_param()
    # ռλ
    g.day_count = 0
    # Ʊֲֺ߼
    g.last_high = {}
    #Ʊ
    # ²ܸ
    if g.is_market_stop_loss_by_price:
        # ¼Ƿ̼۸ֹÿ̺
        g.is_day_stop_loss_by_price = False

    # ѻж״̬
    g.is_last_day_3_black_crows = False
    if g.is_market_stop_loss_by_3_black_crows:
        g.cur_drop_minute_count = 0

    if g.is_rank_stock:
        if g.rank_stock_count > g.pick_stock_count:
            g.rank_stock_count = g.pick_stock_count

    if g.is_stock_stop_loss or g.is_stock_stop_profit:
        # 浱ո2503Ƿ⵱շȡÿ̺
        g.pct_change = {}

    if g.is_market_stop_loss_by_28_index:
        g.minute_count_28index_drop = 0

    if g.is_equity_curve_protect:
        # ¼Ƿʽ߱ÿ̺
        g.is_day_curve_protect = False
    g.time1 = time.time()
    file = StringIO(read_file('pre_result_csv.csv'))
    #print(StringIO(file))
    g.data_ = pd.read_csv(file,index_col = 0)
    # ӡԲ
    log_param()
def set_param():
    # Ƶʣλ
    g.period = 3
    # õʱ䣨24Сʱƣ
    g.adjust_position_hour = 14
    g.adjust_position_minute = 50
    # ѡɲ

    # ѡƱĿ
    g.pick_stock_count = 100
    
    # ѡɲ
    # ǷPEѡ
    g.pick_by_pe = False
    # PEѡɣСPEֵ
    if g.pick_by_pe:
        g.max_pe = 200
        g.min_pe = 0

    # ǷEPSѡ
    g.pick_by_eps = False
    # ѡСEPSֵ
    if g.pick_by_eps:
        g.min_eps = 0
    
    # Ƿ˴ҵƱ
    g.filter_gem = False
    # Ƿ˺Ʊز⽨رգģʱ
    g.filter_blacklist = False

    # ǷԹƱ
    g.is_rank_stock = False
    if g.is_rank_stock:
        # ֵĹƱĿ
        g.rank_stock_count = 20

    # ƱĿ
    g.buy_stock_count = 5
    
    # öָ
    #g.index2 = '000300.XSHG'  # 300ָʾ̹
    #g.index8 = '000905.XSHG'  # ֤500ָʾˣС̹
    g.index2 = '000016.XSHG'  # ֤50ָ
    g.index8 = '399333.XSHE'  # СRָ
    #g.index8 = '399006.XSHE'  # ҵָ
    
    # жֵĶָ20
    #g.index_growth_rate = 0.00
    g.index_growth_rate = 0.01
    
    #趨
    g.bbands = True
    g.ema = True
    g.cci = True
    g.kd = True
    g.dif = True
    g.macd = True
    g.rsi = True
    g.bais = True
    # Ƿݴʷ۸ֹ
    # ָǰ130߼۳ͼ2ֹ
    # עرմֹӣس
    g.is_market_stop_loss_by_price = False
    if g.is_market_stop_loss_by_price:
        # ü۸ֹжָĬΪָ֤޸Ϊָ
        g.index_4_stop_loss_by_price = '000001.XSHG'

    # ѻжָĬΪָ֤޸Ϊָ
    g.index_4_stop_loss_by_3_black_crows = '000001.XSHG'

    # Ƿѻֹ
    # ΪԴжѻЧãЧֻѻжϣ׼ȷʵҲã
    # Σʷ鿴һֻ̳ѻʱѾͺˣʹֹʽܻ
    g.is_market_stop_loss_by_3_black_crows = False
    if g.is_market_stop_loss_by_3_black_crows:
        g.dst_drop_minute_count = 60

    # Ƿ28ֵָʵʱֹ
    g.is_market_stop_loss_by_28_index = False
    if g.is_market_stop_loss_by_28_index:
        # õ28ָΪķӼﵽֵָֹ
        g.dst_minute_count_28index_drop = 30

    # Ƿֹ
    g.is_stock_stop_loss = False
    # Ƿֹӯ
    g.is_stock_stop_profit = False
    
    # Ƿʽ߱
    g.is_equity_curve_protect = False
    if g.is_equity_curve_protect:
        # ʽ߲
        g.value_list = []
    
    
def log_param():
    log.info("Ƶ: %d" %(g.period))
    log.info("ʱ: %s:%s" %(g.adjust_position_hour, g.adjust_position_minute))

    log.info("ѡƱĿ: %d" %(g.pick_stock_count))

    log.info("ǷPEѡ: %s" %(g.pick_by_pe))
    if g.pick_by_pe:
        log.info("ѡPE: %s" %(g.max_pe))
        log.info("ѡСPE: %s" %(g.min_pe))

    log.info("ǷEPSѡ: %s" %(g.pick_by_eps))
    if g.pick_by_eps:
        log.info("ѡСEPS: %s" %(g.min_eps))
    
    log.info("Ƿ˴ҵƱ: %s" %(g.filter_gem))
    log.info("Ƿ˺Ʊ: %s" %(g.filter_blacklist))
    if g.filter_blacklist:
        log.info("ǰƱ%s" %str(get_blacklist()))

    log.info("ǷԹƱѡ: %s" %(g.is_rank_stock))
    if g.is_rank_stock:
        log.info("ֱѡƱĿ: %d" %(g.rank_stock_count))

    log.info("ƱĿ: %d" %(g.buy_stock_count))

    log.info("ָ֮: %s - %s" %(g.index2, get_security_info(g.index2).display_name))
    log.info("ָ֮: %s - %s" %(g.index8, get_security_info(g.index8).display_name))
    log.info("жֵĶָ20: %.1f%%" %(g.index_growth_rate*100))

    log.info("Ƿʷߵͼ۸ֹ: %s" %(g.is_market_stop_loss_by_price))
    if g.is_market_stop_loss_by_price:
        log.info("̼۸ֹжָ: %s - %s" %(g.index_4_stop_loss_by_price, get_security_info(g.index_4_stop_loss_by_price).display_name))

    log.info("Ƿѻֹ: %s" %(g.is_market_stop_loss_by_3_black_crows))
    if g.is_market_stop_loss_by_3_black_crows:
        log.info("ѻֹжָ: %s - %s" %(g.index_4_stop_loss_by_3_black_crows, get_security_info(g.index_4_stop_loss_by_3_black_crows).display_name))
        log.info("ѻֹҪմΪķӼﵽ: %d" %(g.dst_drop_minute_count))

    log.info("Ƿ28ֵָʵʱֹ: %s" %(g.is_market_stop_loss_by_28_index))
    if g.is_market_stop_loss_by_28_index:
        log.info("28ָֹҪ28ָΪķӼﵽ: %d" %(g.dst_minute_count_28index_drop))        

    log.info("Ƿֹ: %s" %(g.is_stock_stop_loss))
    log.info("Ƿֹӯ: %s" %(g.is_stock_stop_profit))
    
    log.info("Ƿʽ߱: %s" %(g.is_equity_curve_protect))

# õղҪҪõĲ
def reset_day_param():
    if g.is_market_stop_loss_by_price:
        # õմ̼۸ֹ״̬
        g.is_day_stop_loss_by_price = False

    # ѻ״̬
    g.is_last_day_3_black_crows = False
    if g.is_market_stop_loss_by_3_black_crows:
        g.cur_drop_minute_count = 0
        
    if g.is_market_stop_loss_by_28_index:
        g.minute_count_28index_drop = 0

    if g.is_stock_stop_loss or g.is_stock_stop_profit:
        # յո2503ǷĻ
        g.pct_change.clear()

    # ʽ߱״̬    
    if g.is_equity_curve_protect:
        g.is_day_curve_protect = False

# ӻز
def handle_data(context, data):
    if g.is_market_stop_loss_by_price:
        if market_stop_loss_by_price(context, g.index_4_stop_loss_by_price):
            return

    if g.is_market_stop_loss_by_3_black_crows:
        if market_stop_loss_by_3_black_crows(context, g.index_4_stop_loss_by_3_black_crows, g.dst_drop_minute_count):
            return

    if g.is_market_stop_loss_by_28_index:
        if market_stop_loss_by_28_index(context, g.dst_minute_count_28index_drop):
            return

    if g.is_stock_stop_loss:
        stock_stop_loss(context, data)

    if g.is_stock_stop_profit:
        stock_stop_profit(context, data)
        
    if g.is_equity_curve_protect:
        if equity_curve_protect(context):
            return

    # õǰʱ
    hour = context.current_dt.hour
    minute = context.current_dt.minute

    # ÿβ̼¼ʲ
    if g.is_equity_curve_protect:
        if hour == 14 and minute == 59:
            g.value_list.append(context.portfolio.total_value)

    # ÿָʱǷֲ
    if hour == g.adjust_position_hour and minute == g.adjust_position_minute:
        do_handle_data(context, data)

def do_handle_data(context, data):
    log.info("ռ [%d]" %(g.day_count))
    # ؿָǰ20Ƿ
    gr_index2 = get_growth_rate(g.index2)
    gr_index8 = get_growth_rate(g.index8)
    log.info("ǰ%sָ20Ƿ [%.2f%%]" %(get_security_info(g.index2).display_name, gr_index2*100))
    log.info("ǰ%sָ20Ƿ [%.2f%%]" %(get_security_info(g.index8).display_name, gr_index8*100))

    if gr_index2 <= g.index_growth_rate and gr_index8 <= g.index_growth_rate:
        clear_position(context)
        g.day_count = 0
    else: #if  gr_index2 > g.index_growth_rate or ret_index8 > g.index_growth_rate:
        if g.day_count % g.period == 0 and g.day_count >= 0:
            log.info("==> е")
            buy_stocks = g.stocks
            log.info("ѡɺƱ: %s" %(buy_stocks))
            adjust_position(context, buy_stocks)
        g.day_count += 1

def market_stop_loss_by_price(context, index):
    # ָǰ130߼۳ͼ2ֹ
    # ʷж״̬㣬춼仯
    # Ӵֹ𣬻سͣ潵

    if not g.is_day_stop_loss_by_price:
        h = attribute_history(index, 160, unit='1d', fields=('close', 'high', 'low'), skip_paused=True)
        low_price = h.low.min()
        high_price = h.high.max()
        #if high_price > 2 * low_price:
        if high_price > 2.2 * low_price \
            and h['close'][-1] < h['close'][-4] \
            and h['close'][-1]> h['close'][-100]:
            # յһ־
            log.info("==> ֹ%sָǰ130߼۳ͼ2, ߼: %f, ͼ: %f" %(get_security_info(index).display_name, high_price, low_price))
            g.is_day_stop_loss_by_price = True

    if g.is_day_stop_loss_by_price:
        clear_position(context)
        g.day_count = 0

    return g.is_day_stop_loss_by_price

# ʽ߱  
def equity_curve_protect(context):
    if not g.is_day_curve_protect:
        cur_value = context.portfolio.total_value
        if len(g.value_list) >= 20:
            last_value = g.value_list[-20]
            #avg_value = sum(g.value_list[-20:]) / 20
            if cur_value < last_value*0.99:
                log.info("==> ʽ߱, 20ǰʲ: %f, ǰʲ: %f" %(last_value, cur_value))
                g.is_day_curve_protect = True

    if g.is_day_curve_protect:
        clear_position(context)
        del g.value_list[:]
        g.day_count = -1

    return g.is_day_curve_protect

def market_stop_loss_by_3_black_crows(context, index, n):
    # ǰѻۼƵմָǷ<0ķӼ
    # Ӽֵnʼѻֹ
    # Чѻֹ
    if g.is_last_day_3_black_crows:
        if get_growth_rate(index, 1) < 0:
            g.cur_drop_minute_count += 1

        if g.cur_drop_minute_count >= n:
            if g.cur_drop_minute_count == n:
                log.info("==> %s < 0 ѳ%dӣִѻֹ" %(get_security_info(index).display_name, n))

            clear_position(context)
            g.day_count = 0
            return True

    return False

def is_3_black_crows(stock):
    # talib.CDL3BLACKCROWS

    # ֻѻ˵԰ٶȰٿ
    # 1. ߣÿ̼۾һյ
    # 2. ǰһгӦΪ
    # 3. ߱Ϊĺɫʵ壬ҳӦô
    # 4. ̼۽ӽÿյͼλ
    # 5. ÿյĿ̼۶ϸKߵʵ岿֮ڣ
    # 6. һߵʵ岿֣õյ߼λ
    #
    # 㷨
    # Чֻѻ˵硣ſֻ12
    # ǰ4ж
    # 3ߵ4.5%ԣ

    h = attribute_history(stock, 4, '1d', ('close','open'), skip_paused=True, df=False)
    h_close = list(h['close'])
    h_open = list(h['open'])

    if len(h_close) < 4 or len(h_open) < 4:
        return False
    
    # һ
    if h_close[-4] > h_open[-4] \
        and (h_close[-1] < h_open[-1] and h_close[-2]< h_open[-2] and h_close[-3] < h_open[-3]):
        #and (h_close[-1] < h_close[-2] and h_close[-2] < h_close[-3]) \
        #and h_close[-1] / h_close[-4] - 1 < -0.045:
        return True
    return False
    

def market_stop_loss_by_28_index(context, count):
    # ؿָǰ20Ƿ
    gr_index2 = get_growth_rate(g.index2)
    gr_index8 = get_growth_rate(g.index8)

    if gr_index2 <= g.index_growth_rate and gr_index8 <= g.index_growth_rate:
        if (g.minute_count_28index_drop == 0):
            log.info("ǰָ20Ƿͬʱ[%.2f%%], %sָ: [%.2f%%], %sָ: [%.2f%%]" \
                %(g.index_growth_rate*100, get_security_info(g.index2).display_name, gr_index2*100, get_security_info(g.index8).display_name, gr_index8*100))

            #log.info("ǰ%sָ20Ƿ [%.2f%%]" %(get_security_info(g.index2).display_name, gr_index2*100))
            #log.info("ǰ%sָ20Ƿ [%.2f%%]" %(get_security_info(g.index8).display_name, gr_index8*100))
        g.minute_count_28index_drop += 1
    else:
        # ״̬
        if g.minute_count_28index_drop < count:
            g.minute_count_28index_drop = 0

    if g.minute_count_28index_drop >= count:
        if g.minute_count_28index_drop == count:
            log.info("==> %sָ%sָ20[%.2f%%]ѳ%dӣִ28ָֹ" \
                %(get_security_info(g.index2).display_name, get_security_info(g.index8).display_name, g.index_growth_rate*100, count))

        clear_position(context)
        g.day_count = 0
        return True
        
    return False

# ֹ
def stock_stop_loss(context, data):
    for stock in context.portfolio.positions.keys():
        cur_price = data[stock].close

        if g.last_high[stock] < cur_price:
            g.last_high[stock] = cur_price

        threshold = get_stop_loss_threshold(stock, g.period)
        #log.debug("ֵֹ, stock: %s, threshold: %f" %(stock, threshold))
        if cur_price < g.last_high[stock] * (1 - threshold):
            log.info("==> ֹ, stock: %s, cur_price: %f, last_high: %f, threshold: %f" 
                %(stock, cur_price, g.last_high[stock], threshold))

            position = context.portfolio.positions[stock]
            if close_position(position):
                g.day_count = 0

# ֹӯ
def stock_stop_profit(context, data):
    for stock in context.portfolio.positions.keys():
        position = context.portfolio.positions[stock]
        cur_price = data[stock].close
        threshold = get_stop_profit_threshold(stock, g.period)
        #log.debug("ֹӯֵ, stock: %s, threshold: %f" %(stock, threshold))
        if cur_price > position.avg_cost * (1 + threshold):
            log.info("==> ֹӯ, stock: %s, cur_price: %f, avg_cost: %f, threshold: %f" 
                %(stock, cur_price, g.last_high[stock], threshold))

            position = context.portfolio.positions[stock]
            if close_position(position):
                g.day_count = 0

# ȡǰnmֵ
# ӻ⵱նλȡ
def get_pct_change(security, n, m):
    pct_change = None
    if security in g.pct_change.keys():
        pct_change = g.pct_change[security]
    else:
        h = attribute_history(security, n, unit='1d', fields=('close'), skip_paused=True)
        pct_change = h['close'].pct_change(m) # 3յİٷֱȱȣ3ǵ
        g.pct_change[security] = pct_change
    return pct_change
        
# ɻسֵֹ
# ڳֲnܳܵ
# 㷨(250nյ + 250ƽnյ)/2
# ֵ
def get_stop_loss_threshold(security, n = 3):
    pct_change = get_pct_change(security, 250, n)
    #log.debug("pct of security [%s]: %s", pct)
    maxd = pct_change.min()
    #maxd = pct[pct<0].min()
    avgd = pct_change.mean()
    #avgd = pct[pct<0].mean()
    # maxdavgdΪʾʱһֱ¹
    bstd = (maxd + avgd) / 2

    # ݲʱbstdΪnan
    if not isnan(bstd):
        if bstd != 0:
            return abs(bstd)
        else:
            # bstd = 0 maxd <= 0
            if maxd < 0:
                # ʱȡ
                return abs(maxd)

    return 0.079 # ĬûزֵֹΪ-9.9%ֵòƻس

# ֹӯֵ
# 㷨250nǷ
# ֵ
def get_stop_profit_threshold(security, n = 3):
    pct_change = get_pct_change(security, 250, n)
    maxr = pct_change.max()
    
    # ݲʱmaxrΪnan
    # maxrΪ
    if (not isnan(maxr)) and maxr != 0:
        return abs(maxr)
    return 0.30 # ĬֹӯֵǷΪ30%

# ȡƱnǷݵǰۼ
# n Ĭ20
def get_growth_rate(security, n=20):
    lc = get_close_price(security, n)
    #c = data[security].close
    c = get_close_price(security, 1, '1m')
    
    if not isnan(lc) and not isnan(c) and lc != 0:
        return (c - lc) / lc
    else:
        log.error("ݷǷ, security: %s, %d̼: %f, ǰ: %f" %(security, n, lc, c))
        return 0

# ȡǰnλʱ䵱ʱ̼
def get_close_price(security, n, unit='1d'):
    return attribute_history(security, n, unit, ('close'), True)['close'][0]

# ֵָ֣֤ȯ
# ɹɽȫɽ򲿷ֳɽʱɽ0True
# ʧܻ߱ɹȡʱɽ0False
def open_position(security, value):
    order = order_target_value_(security, value)
    if order != None and order.filled > 0:
        # ɹгɽʼ߼
        cur_price = get_close_price(security, 1, '1m')
        g.last_high[security] = cur_price
        return True
    return False

# ƽֲָ֣
# ƽֳɹȫɽTrue
# ʧܻ߱ɹȡʱɽ0߱ȫɽFalse
def close_position(position):
    security = position.security
    order = order_target_value_(security, 0) # ܻͣʧ
    if order != None:
        if order.filled > 0:
            # ֻҪгɽȫɽǲֳɽͳӯ
            g.trade_stat.watch(security, order.filled, position.avg_cost, position.price)

        if order.status == OrderStatus.held and order.filled == order.amount:
            # ȫɽɾ֤ȯ߼ۻ
            if security in g.last_high:
                g.last_high.pop(security)
            else:
                log.warn("last high price of %s not found" %(security))
            return True

    return False

# гֲ
def clear_position(context):
    if context.portfolio.positions:
        log.info("==> ֣йƱ")
        for stock in context.portfolio.positions.keys():
            position = context.portfolio.positions[stock]
            close_position(position)

# Զµ
# JoinquantĵǰִУorder_target_valueؼʾ
# ɹرһɽ򷵻None
def order_target_value_(security, value):
    if value == 0:
        log.debug("Selling out %s" % (security))
    else:
        log.debug("Order %s to value %f" % (security, value))
        
    # Ʊͣƣʧܣorder_target_value None
    # Ʊǵͣɹorder_target_value OrderǱȡ
    # ɲıۿ״̬ѳʱɽ>0ͨɽжǷгɽ
    return order_target_value(security, value)


# ͣƹƱ
def filter_paused_stock(stock_list):
    current_data = get_current_data()
    return [stock for stock in stock_list if not current_data[stock].paused]

# STбǩĹƱ
def filter_st_stock(stock_list):
    current_data = get_current_data()
    return [stock for stock in stock_list 
        if not current_data[stock].is_st 
        and 'ST' not in current_data[stock].name 
        and '*' not in current_data[stock].name 
        and '' not in current_data[stock].name]
        
# ͣĹƱ
def filter_limitup_stock(context, stock_list):
    last_prices = history(1, unit='1m', field='close', security_list=stock_list)
    current_data = get_current_data()
    
    # ѴڳֲֵĹƱʹͣҲˣ˹Ʊٴο򣬵򱻹˶ѡĹƱ
    return [stock for stock in stock_list if stock in context.portfolio.positions.keys() 
        or last_prices[stock][-1] < current_data[stock].high_limit]
    #return [stock for stock in stock_list if stock in context.portfolio.positions.keys() 
    #    or last_prices[stock][-1] < current_data[stock].high_limit * 0.995]

# ˵ͣĹƱ
def filter_limitdown_stock(context, stock_list):
    last_prices = history(1, unit='1m', field='close', security_list=stock_list)
    current_data = get_current_data()
    
    return [stock for stock in stock_list if stock in context.portfolio.positions.keys() 
        or last_prices[stock][-1] > current_data[stock].low_limit]
    #return [stock for stock in stock_list if last_prices[stock][-1] > current_data[stock].low_limit]
    #return [stock for stock in stock_list if stock in context.portfolio.positions.keys() 
    #    or last_prices[stock][-1] > current_data[stock].low_limit * 1.005]
    
# ˺Ʊ
def filter_blacklist_stock(context, stock_list):
    blacklist = get_blacklist()
    return [stock for stock in stock_list if stock not in blacklist]

# ˴ҵƱ
def filter_gem_stock(context, stock_list):
    return [stock for stock in stock_list if stock[0:3] != '300']

# 20ΪĹƱ
def filter_by_growth_rate(stock_list, n):
    return [stock for stock in stock_list if get_growth_rate(stock, n) > 0]

# Ʊ
def rank_stocks(data, stock_list):
    dst_stocks = {}
    for stock in stock_list:
        h = attribute_history(stock, 130, unit='1d', fields=('close', 'high', 'low'), skip_paused=True)
        low_price_130 = h.low.min()
        high_price_130 = h.high.max()

        avg_15 = data[stock].mavg(15, field='close')
        cur_price = data[stock].close

        #avg_15 = h['close'][-15:].mean()
        #cur_price = get_close_price(stock, 1, '1m')

        score = (cur_price-low_price_130) + (cur_price-high_price_130) + (cur_price-avg_15)
        #score = ((cur_price-low_price_130) + (cur_price-high_price_130) + (cur_price-avg_15)) / cur_price
        dst_stocks[stock] = score
        
    df = pd.DataFrame(dst_stocks.values(), index=dst_stocks.keys())
    df.columns = ['score']
    df = df.sort(columns='score', ascending=True)
    return df.index


# ¹
def filter_new_stock(stock_list):
    stocks = get_all_securities(['stock'])
    stocks = stocks[(context.current_dt.date() - stocks.start_date) > datetime.timedelta(90)].index
    return stocks

# ѡ
# ѡȡָĿСֵƱٽйˣѡָĿĹƱ
def pick_stocks(context, data):
    q = query(valuation.code)
    if g.pick_by_pe:
        q = q.filter(
            valuation.pe_ratio > g.min_pe, 
            valuation.pe_ratio < g.max_pe
            )

    if g.pick_by_eps:
        q = q.filter(
            indicator.eps > g.min_eps,
            #valuation.turnover_ratio > 3
            )

    q = q.order_by(
                valuation.market_cap.asc()
            ).limit(
                g.pick_stock_count
            )
    
    df = get_fundamentals(q)
    stock_list = list(df['code'])

    if g.filter_gem:
        stock_list = filter_gem_stock(context, stock_list)
        
    if g.filter_blacklist:
        stock_list = filter_blacklist_stock(context, stock_list)
        
    stock_list = filter_paused_stock(stock_list)
    stock_list = filter_st_stock(stock_list)
    stock_list = filter_limitup_stock(context, stock_list)
    stock_list = filter_limitdown_stock(context, stock_list)

    # 20չƱǷЧãע
    #stock_list = filter_by_growth_rate(stock_list, 20)
    
    if g.is_rank_stock:
        if len(stock_list) > g.rank_stock_count:
            stock_list = stock_list[:g.rank_stock_count]

        #log.debug("ǰѡƱ: %s" %(stock_list))
        if len(stock_list) > 0:
            stock_list = rank_stocks(data, stock_list)
        #log.debug("ֺѡƱ: %s" %(stock_list))
    
    # ѡȡָĿĹƱ
    if len(stock_list) > g.buy_stock_count:
        stock_list = stock_list[:g.buy_stock_count]
    return stock_list

# ݴƱλ
# ͣƵԭûĹƱ
# ʼձֲֳĿΪg.buy_stock_count
def adjust_position(context, buy_stocks):
    for stock in context.portfolio.positions.keys():
        if stock not in buy_stocks:
            log.info("stock [%s] in position is not buyable" %(stock))
            position = context.portfolio.positions[stock]
            close_position(position)
        else:
            log.info("stock [%s] is already in position" %(stock))
    
    # ݹƱֲ
    # ˴ֻݿýƽ乺򣬲ܱ֤ÿλƽ
    position_count = len(context.portfolio.positions)
    if g.buy_stock_count > position_count:
        value = context.portfolio.cash / (g.buy_stock_count - position_count)

        for stock in buy_stocks:
            if context.portfolio.positions[stock].total_amount == 0:
                if open_position(stock, value):
                    if len(context.portfolio.positions) == g.buy_stock_count:
                        break


